home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
mint
/
toswinsc.zoo
/
textwin.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-27
|
30KB
|
1,257 lines
/*
* Copyright 1992 Eric R. Smith. All rights reserved.
* Redistribution is permitted only if the distribution
* is not for profit, and only if all documentation
* (including, in particular, the file "copying")
* is included in the distribution in unmodified form.
* THIS PROGRAM COMES WITH ABSOLUTELY NO WARRANTY, NOT
* EVEN THE IMPLIED WARRANTIES OF MERCHANTIBILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. USE AT YOUR OWN
* RISK.
*/
#include "xgem.h"
#include <stdlib.h>
#define CLEARED 2 /* redrawing a cleared area */
int default_height = 10; /* default font height (points) */
int default_font = 1; /* default font (pixels) */
int align_windows = 0; /* align windows on byte boundaries */
/* if a font doesn't define a character, use this one instead */
#define DEFAULT_CHAR '?'
static void set_cwidths __PROTO((TEXTWIN *));
/* functions for converting x, y pixels to/from character coordinates */
/* NOTES: these functions give the upper left corner; to actually draw
* a character, they must be adjusted down by t->cbase
* Also: char2pixel accepts out of range character/column combinations,
* but pixel2char never will generate such combinations.
*/
void
char2pixel(t, col, row, xp, yp)
TEXTWIN *t;
int col, row;
int *xp, *yp;
{
short *WIDE = t->cwidths;
int x;
*yp = t->win->wi_y - t->offy + row * t->cheight;
if (!WIDE) {
*xp = t->win->wi_x - t->offx + col * t->cmaxwidth;
} else if (col >= t->maxx) {
*xp = t->win->wi_x + t->win->wi_w;
} else {
x = t->win->wi_x - t->offx;
while(--col >= 0) {
x += WIDE[t->data[row][col]];
}
*xp = x;
}
}
void
pixel2char(t, x, y, colp, rowp)
TEXTWIN *t;
int x, y, *colp, *rowp;
{
int col, row, count, nextcount;
short *WIDE = t->cwidths;
row = (y - t->win->wi_y + t->offy) / t->cheight;
x = x - t->win->wi_x + t->offx;
if (WIDE == 0) {
col = x / t->cmaxwidth;
} else {
count = 0;
for (col = 0; col < t->maxx - 1; col++) {
nextcount = count + WIDE[t->data[row][col]];
if (count <= x && x < nextcount) break;
count = nextcount;
}
}
*rowp = row;
*colp = col;
}
static void set_scroll_bars __PROTO((TEXTWIN *));
/*
* draw a (part of a) line on screen, with certain attributes (e.g.
* inverse video) indicated by "flag". (x, y) is the upper left corner
* of the box which will contain the line.
* If "force" is 1, we may assume that the screen is already cleared
* (this is done in update_screen() for us).
* SPECIAL CASE: if buf is an empty string, we clear from "x" to
* the end of the window.
*/
static void
draw_buf(t, buf, x, y, flag, force)
TEXTWIN *t;
char *buf;
int x, y, flag, force;
{
char *s, *lastnonblank;
int x2, fillcolor, textcolor;
int texteffects;
short *WIDE = t->cwidths;
int temp[4];
fillcolor = flag & CBGCOL;
textcolor = (flag & CFGCOL) >> 4;
texteffects = (flag & CEFFECTS) >> 8;
#ifdef STIPPLE_SELECT
if (flag & CINVERSE) { /* swap foreground and background */
x2 = fillcolor; fillcolor = textcolor; textcolor = x2;
}
#else
if (flag & (CINVERSE|CSELECTED)) { /* swap foreground and background */
x2 = fillcolor; fillcolor = textcolor; textcolor = x2;
}
#endif
x2 = x;
s = buf;
if (*s) {
lastnonblank = s-1;
while (*s) {
if (*s != ' ') lastnonblank = s;
if (WIDE)
x2 += WIDE[*s];
else
x2 += t->cmaxwidth;
s++;
}
lastnonblank++;
if (!(flag & CE_UNDERLINE))
*lastnonblank = 0;
} else {
x2 = t->win->wi_x + t->win->wi_w;
}
set_wrmode(2); /* transparent text */
if (fillcolor != 0 || (force != CLEARED)) {
/* the background may not be set correctly, so we do it here */
temp[0] = x;
temp[1] = y;
temp[2] = x2 - 1;
temp[3] = y + t->cheight - 1;
set_fillcolor(fillcolor);
set_fillstyle(1, 1); /* fill the area completely */
v_bar(vdi_handle, temp);
}
/* skip leading blanks -- we don't need to draw them again! */
if (!(flag & CE_UNDERLINE)) {
while (*buf == ' ') {
buf++;
x += WIDE ? WIDE[' '] : t->cmaxwidth;
}
}
if (*buf) {
set_textcolor(textcolor);
set_texteffects(texteffects);
v_gtext(vdi_handle, x, y + t->cbase, buf);
}
#ifdef STIPPLE_SELECT
if (flag & CSELECTED) { /* put in the pattern */
set_wrmode(2); /* 'OR' the pattern */
set_fillstyle(2, 2);
set_fillcolor(textcolor);
v_bar(vdi_handle, temp);
}
#endif
}
/*
* update the characters on screen between "firstline,firstcol" and
* "lastline-1,lastcol-1" (inclusive)
* if force == 1, the redraw must occur, otherwise it occurs only for
* "dirty" characters. Note that we assume here that clipping
* rectanges and wind_update() have already been set for us.
*/
static void
update_chars(t, firstcol, lastcol, firstline, lastline, force)
TEXTWIN *t;
int firstcol, lastcol, firstline, lastline, force;
{
#define CBUFSIZ 127
UCHAR buf[CBUFSIZ+1], c;
int px, py, ax, i, cnt, flag, bufwidth;
short *WIDE = t->cwidths;
int lineforce = 0;
int curflag;
#define flushbuf() \
{ buf[i] = 0; \
draw_buf(t, buf, px, py, flag, lineforce); \
px += bufwidth; \
i = bufwidth = 0; \
}
/* make sure the font is set correctly */
set_font(t->cfont, t->cpoints);
/* find the place to start writing */
char2pixel(t, firstcol, firstline, &ax, &py);
/* now write the characters we need to */
while (firstline < lastline) {
/* if no characters on the line need re-writing, skip the loop */
if (!force && t->dirty[firstline] == 0) {
py += t->cheight;
firstline++;
continue;
}
px = ax;
/*
* now, go along collecting characters to write into the buffer
* we add a character to the buffer if and only if (1) the
* character's attributes (inverse video, etc.) match the
* attributes of the character already in the buffer, and
* (2) the character needs redrawing. Otherwise, if there are
* characters in the buffer, we flush the buffer.
*/
i = bufwidth = 0;
cnt = firstcol;
flag = 0;
lineforce = force;
if (!lineforce && (t->dirty[firstline] & ALLDIRTY))
lineforce = 1;
while (cnt < lastcol) {
c = t->data[firstline][cnt];
if (lineforce ||
(t->cflag[firstline][cnt] & (CDIRTY|CTOUCHED))) {
/* yes, this character needs drawing */
/* if the font is proportional and the character has really changed,
* then all remaining characters will have to be redrawn, too
*/
if (WIDE && (lineforce == 0) &&
(t->cflag[firstline][cnt] & CDIRTY))
lineforce = 1;
/* watch out for characters that can't be drawn in this font */
if (c < t->minADE || c > t->maxADE)
c = DEFAULT_CHAR;
curflag = t->cflag[firstline][cnt] & ~(CDIRTY|CTOUCHED);
if (flag == curflag) {
buf[i++] = c;
bufwidth += (WIDE ? WIDE[c] : t->cmaxwidth);
if (i == CBUFSIZ) {
flushbuf();
}
} else {
if (i) {
flushbuf();
}
flag = curflag;
buf[i++] = c;
bufwidth += (WIDE ? WIDE[c] : t->cmaxwidth);
}
} else {
if (i) {
flushbuf();
}
px += (WIDE ? WIDE[c] : t->cmaxwidth);
}
cnt++;
}
if (i) {
flushbuf();
}
if (WIDE) { /* the line's 'tail' */
draw_buf(t, "", px, py, t->cflag[firstline][t->maxx-1],
lineforce);
}
py += t->cheight;
firstline++;
}
}
/*
* mark_clean: mark a window as having been completely updated
*/
void
mark_clean(t)
TEXTWIN *t;
{
int line, col;
for (line = 0; line < t->maxy; line++) {
if (t->dirty[line] == 0)
continue;
for (col = 0; col < t->maxx; col++) {
t->cflag[line][col] &= ~(CDIRTY|CTOUCHED);
}
t->dirty[line] = 0;
}
}
/*
* redraw all parts of window v which are contained within the
* given rectangle. Assumes that the clipping rectange has already
* been set correctly.
* NOTE: more than one rectangle may cover the same area, so we
* can't mark the window clean during the update; we have to do
* it in a separate routine (mark_clean)
*/
static MFDB scr_mfdb; /* left NULL so it refers to the screen by default */
stat